﻿/**

 * Copyright (c) 2015-2016, FastDev 刘强 (fastdev@163.com) & Quincy.

 *

 * Licensed under the Apache License, Version 2.0 (the "License");

 * you may not use this file except in compliance with the License.

 * You may obtain a copy of the License at

 *

 *      http://www.apache.org/licenses/LICENSE-2.0

 *

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS,

 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 * See the License for the specific language governing permissions and

 * limitations under the License.

 */

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace OF.Notify.DataHost.Cluster.Disk
{
    public class DiskVisitor
    {
        public static void SafeCreateFile(string filePath, Action<FileStream> action)
        {
            if (File.Exists(filePath))
            {
                return;
            }
            ClusterContext.StringLock.Invoke(filePath, () =>
            {
                if (File.Exists(filePath))
                {
                    return;
                }
                EnsureFileDirectoryExists(filePath);
                using (FileStream fs = new FileStream(filePath, FileMode.Append))
                {
                    if (action != null)
                    {
                        action(fs);
                    }
                }
            });
        }

        public static void SafeDeleteFile(string file)
        {
            ClusterContext.StringLock.Invoke(file, () => {
                if (File.Exists(file))
                {
                    File.Delete(file);
                } 
            });
        }

        public static void SafeDeleteDir(string dir)
        {
            if (Directory.Exists(dir))
            {
                try
                {
                    Directory.Delete(dir, true);
                }
                catch (Exception ex)
                { }
            }
        }

        public static void SafeMoveFile(string source, string dest)
        {
            if (!File.Exists(source))
            {
                return;
            }

            ClusterContext.StringLock.Invoke(dest, () => {
                if (File.Exists(dest))
                {
                    File.Delete(dest);
                    File.Move(source, dest);
                }
                else
                {
                    EnsureFileDirectoryExists(dest);
                    File.Move(source, dest);
                }
            });
        }

        public static void TryCreateDir(string folderPath)
        {
            if (!Directory.Exists(folderPath))
            {
                try
                {
                    Directory.CreateDirectory(folderPath);
                }
                catch (Exception ex)
                {

                }
            }
        }

        public static void EnsureFileDirectoryExists(string filePath)
        {
            string folderPath = filePath.Substring(0, filePath.LastIndexOf("\\"));
            TryCreateDir(folderPath);
        }

        public static void SequenceVisitFiles(string basePath, Func<string, bool> fileVisitor)
        {
            Stack<string> dirStack = new Stack<string>();
            Func<string, int> orderByFolderFunc = (path) =>
            {
                return -int.Parse(path.Substring(path.LastIndexOf("\\") + 1));
            };

            Func<string, int> orderByFileFunc = (path) =>
            {
                return int.Parse(path.Substring(path.LastIndexOf("\\") + 1));
            };
            if (Directory.Exists(basePath))
            {
                dirStack.Push(basePath);
            }
            while (dirStack.Count > 0)
            {
                string dir = dirStack.Pop();
                var childDirs = Directory.EnumerateDirectories(dir).OrderBy(orderByFolderFunc);
                foreach (var childDir in childDirs)
                {
                    dirStack.Push(childDir);
                }

                var childFiles = Directory.EnumerateFiles(dir).OrderBy(orderByFileFunc);
                foreach(var file in childFiles)
                {
                    if (fileVisitor(file))
                    {
                        return;
                    }
                }
            }
        }
    }
}
